use ash::vk;

use crate::{vulkan::VkContext, VK_LOGD};

use super::RenderSystem;

pub struct PerFrameUniformData {
    pub view_proj_mat: cgmath::Matrix4<f32>
}

pub struct Camera {
    location        : cgmath::Point3<f32>,
    look_at         : cgmath::Point3<f32>,
    up_dir          : cgmath::Vector3<f32>,

    fov             : f32,
    near            : f32,
    far             : f32
}

impl Default for Camera {
    fn default() -> Self {
        Self {
            location    : cgmath::Point3  { x: -20.0, y: -20.0, z:  0.0 },
            look_at     : cgmath::Point3  { x: 0.0, y: 0.0, z:  0.0 },
            up_dir      : cgmath::Vector3 { x: 0.0, y: 0.0, z: -1.0 },

            fov         : 60.0f32,
            near        : 0.1f32,
            far         : 100.0f32
        }
    }
}

impl Camera {
    pub fn get_view_mat(&self) -> cgmath::Matrix4<f32> {
        cgmath::Matrix4::look_at_rh(self.location, self.look_at, self.up_dir)
    }

    pub fn get_proj_mat(&self, extent: &vk::Extent2D) -> cgmath::Matrix4<f32> {
        cgmath::perspective(cgmath::Deg(self.fov), extent.width as f32 / extent.height as f32, self.near, self.far)
    }

    pub fn get_view_proj_mat(&self, extent: &vk::Extent2D) -> cgmath::Matrix4<f32> {
        self.get_proj_mat(extent) * self.get_view_mat()
    }
}

impl RenderSystem {
    pub fn generate_per_frame_uniform(&self) -> PerFrameUniformData {
        let camera              = &self.camera;
        let swapchain_extent    = self.swapchain.get_extent();

        PerFrameUniformData {
            view_proj_mat: camera.get_view_proj_mat(&swapchain_extent)
        }
    }
}